package com.trytech.mongoocrawler.client;

import com.trytech.mongoocrawler.client.common.http.CrawlerHttpRequest;
import com.trytech.mongoocrawler.client.common.http.factory.CrawlerHttpReqFactory;
import com.trytech.mongoocrawler.client.common.queue.DisruptorContext;
import com.trytech.mongoocrawler.client.parser.jd.JDBookCate1Parser;
import com.trytech.mongoocrawler.client.transport.LocalUrlManager;
import com.trytech.mongoocrawler.client.transport.TaskThreadPool;
import com.trytech.mongoocrawler.client.transport.TaskWorker;
import com.trytech.mongoocrawler.client.transport.UrlManager;
import org.apache.commons.lang3.StringUtils;

import java.net.URL;
import java.util.UUID;

/**
 * 一次爬取会话
 * 会话的生命周期包括：
 *      INITIALIZED=0-初始化
 *      RUNNING=1-已运行
 *      PAUSED=2-暂停
 *      DESTORYED=3-已销毁
 */
public class CrawlerSession {
    //父容器
    private CrawlerContext container;
    //会话ID
    private String sessionId;
    //会话ID生成器
    private SessionIdGenerator generator = new SessionIdGenerator();
    //生命周期
    private LifeCycle lifeCycle;
    //url内存队列
    protected UrlManager urlManager = new LocalUrlManager();
    //工作线程池
    private TaskThreadPool threadPool = new TaskThreadPool();
    //Disruptor上下文
    private DisruptorContext disruptorContext;

    private enum RUN_MODE{
        NON_STOP(1), STATUS_MONITOR(2),RUN_UNTIL_EMPTY(3);
        private int mode;
        private RUN_MODE(int mode){
            this.mode = mode;
        }
        public int getMode(){
            return mode;
        }

        public static RUN_MODE parseMode(int mode){
            switch (mode){
                case 3:
                    return RUN_UNTIL_EMPTY;
                case 2:
                    return STATUS_MONITOR;
                default:
                    return NON_STOP;
            }
        }
    }
    //生命周期
    public enum LifeCycle{
        INITIALIZED(0),RUNNING(1),PAUSED(2),DESTORYED(3);
        private int status;
        LifeCycle(int status){
            this.status = status;
        }
        public int getStatus(){
            return status;
        }
    }

    /***
     * 构造函数
     * @param container 父容器
     */
    public CrawlerSession(CrawlerContext container,String[] startsUrls){
        this.container = container;
        lifeCycle = LifeCycle.INITIALIZED;
        if(startsUrls != null) {
            this.urlManager.pushUrls(startsUrls);
        }
        disruptorContext = DisruptorContext.getInstance(this);
    }
    public CrawlerSession(CrawlerContext container,String[] startsUrls,UrlManager urlManager){
        this.container = container;
        lifeCycle = LifeCycle.INITIALIZED;
        this.urlManager = urlManager;
        if(startsUrls != null) {
            this.urlManager.pushUrls(startsUrls);
        }
        disruptorContext = DisruptorContext.getInstance(this);
    }
    public String getSessionId() {
        return generator.generate();
    }

    public void start(){
        RUN_MODE runMode = RUN_MODE.parseMode(container.getConfig().getRunMode());
        //启动disruptor
        if(!disruptorContext.isStarted()){
            disruptorContext.start();
        }
        //如果该会话已启动或已销毁均不能再启动
        if(lifeCycle != LifeCycle.DESTORYED && lifeCycle != LifeCycle.RUNNING){
            while (true){
                try {
                    URL url = urlManager.popUrl();
                    if(url == null && runMode == RUN_MODE.RUN_UNTIL_EMPTY){
                        break;
                    }
                    if(url != null) {
                        System.out.println("正在爬取url:" + url.toString());
                        CrawlerHttpRequest request = CrawlerHttpReqFactory.getRequest(url,new JDBookCate1Parser());
                        threadPool.submit(new TaskWorker(request,this));
                    }
                }catch (Exception e){

                }
                if(runMode == RUN_MODE.STATUS_MONITOR){
                    if(lifeCycle == LifeCycle.DESTORYED){
                        destory();
                        break;
                    }
                }
            }
        }
        lifeCycle = LifeCycle.RUNNING;
    }

    public void pause(){
        lifeCycle = LifeCycle.PAUSED;
    }
    public void destory(){
        lifeCycle = LifeCycle.DESTORYED;
        container.removeSession(sessionId);
        container = null;
    }

    public DisruptorContext getDisruptorContext(){
        return disruptorContext;
    }

    public void submitTask(CrawlerHttpRequest request){
        threadPool.submit(new TaskWorker(request,this));
    }
    private class SessionIdGenerator{
        public String generate(){
            if(StringUtils.isEmpty(sessionId)) {
                sessionId = UUID.randomUUID().toString();
            }
            return sessionId;
        }
    }
}
